package org.example.tx;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class TxWorker {

    private final ThreadManager threadManager = new ThreadManager();

    @Autowired
    private TxService txService;

    public void run() throws InterruptedException {
        for (int i = 0; i < 4; i++) {
            threadManager.startThread(new ReadWorker(txService));
        }

        for (int i = 0; i < 4; i++) {
            threadManager.startThread(new WriteWorker(txService));
        }

        threadManager.waitAllThreads();
    }

    static class ThreadManager {

        private final List<Thread> threads = new ArrayList<>();

        void startThread(Thread thread) {
            threads.add(thread);
            thread.start();
        }

        void waitAllThreads() throws InterruptedException {
            for (Thread thread : threads) {
                thread.join();
            }
        }
    }

    static abstract class BaseWorker extends Thread {

        public BaseWorker(String name) {
            super(name);
        }

        @Override
        public void run() {
            onStart();
            doRun();
            onEnd();
        }

        abstract protected void doRun();

        protected void onStart() {
            log.info("worker started");
        }

        protected void onEnd() {
            log.info("worker end");
        }
    }

    static class ReadWorker extends BaseWorker {

        private static final Sequence seq = new Sequence();

        private final TxService txService;

        public ReadWorker(TxService txService) {
            super("reader-" + seq.next());
            this.txService = txService;
        }

        @Override
        protected void doRun() {
            for (int i = 0; i < 10; i++) {
                txService.read();
            }
        }
    }

    static class WriteWorker extends BaseWorker {

        private static final Sequence seq = new Sequence();

        private final TxService txService;

        public WriteWorker(TxService txService) {
            super("writer-" + seq.next());
            this.txService = txService;
        }

        @Override
        protected void doRun() {
            for (int i = 0; i < 10; i++) {
                txService.write();
            }
        }
    }
}
